home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK1.toast / Development Kits (Disc 1) / MacTCP / MacTCP Developer Tools / 802 LAP / LAP802Arp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-21  |  12.5 KB  |  450 lines  |  [TEXT/MPS ]

  1. /* LAP802Arp.c     contains Address Resolution Protocol handler for IEEE 802.3 LAP
  2.  
  3.    (c) Copyright 1990-91 by Apple Computer, Inc.  All rights reserved.
  4.    
  5. */
  6.  
  7. /*
  8.     1.2        Oct 1990    Rajesh - modified to add IEEE 802.3 LAP flavor.
  9.     1.0d4    7/13/88    JEM    Fixed IOComplete on ARP time-out
  10.             6/10/88    JEM    Put LAP's into separate code segments
  11.      1.0d2    1/13/88    JEM Convert to MPW
  12.     1.0d1    9/14/87    JEM    Initial version for MacOS
  13. */
  14.  
  15. #include <OSUtils.h>
  16. #include <Retrace.H>
  17. #include <Devices.h>
  18. #include <Memory.h>
  19. #include <Traps.h>
  20. #include <AppleTalk.h>
  21.  
  22. #include "MacTCPCommonTypes.h"
  23. #include "MiscIPPB.h"
  24. #include "LAPMisc.h"
  25. #include "LAP802.h"
  26.  
  27. #define MAX_AGE            10*60*6        /* time-out ARP cache entry if unused for 10 minutes */
  28. #define MAX_RTX            4            /* RTX ARP request 4 times */
  29.  
  30. #define ARP_VRT_COUNT    10            /* RTX ARP every 160 msec. */
  31. #define ARP_VRT_PHASE    5
  32.  
  33.  
  34. /* internal procedure prototype definitions */
  35. pascal void Arp_vrt_handler(void);
  36.  
  37. struct arp_entry *new_arp_entry(struct Lap802Info *lap, b_16 prot, Lap802_addr sha, ip_addr spa);
  38. struct arp_entry *get_arp_entry(struct Lap802Info *lap, ip_addr addr);
  39.  
  40. extern void Enable(short oldPS);
  41. extern short Disable(void);
  42. extern Boolean broadcastAddr(struct LAPInfo *lap, ip_addr addr);
  43.  
  44.  
  45. OSErr Arp_init(lap)
  46. struct Lap802Info *lap;
  47. {        
  48.     struct ipbuf *ipb;
  49.     struct Lap802_header *lap_hdr;
  50.     struct arp_header *arp_hdr;
  51.         
  52.     bzero((char *)&lap->arp_q, sizeof(lap->arp_q));
  53.     bzero((char *)&lap->arp_table[0], sizeof(lap->arp_table));
  54.  
  55.     /* set-up ARP sending IPB */
  56.     ipb = (struct ipbuf *) NewPtr(sizeof(struct ipbuf) + 
  57.         sizeof(struct Lap802_header) + sizeof(struct arp_header));
  58.     lap->arp_ipb = ipb;
  59.     bzero((char *)ipb, sizeof(struct ipbuf));
  60.  
  61.     lap_hdr = (struct Lap802_header *)(ipb+1);
  62.     ipb->laphdr.ptr = (char *)lap_hdr;
  63.     ipb->laphdr.length = sizeof(struct Lap802_header);
  64.         /* lap_len can be zero, since we always calculate length before writing */
  65.     lap_hdr->lap_len = sizeof(struct arp_header) + 8; /* sizeof(struct LLC_SNAP_header) = 3,LLC + 5,SNAP = 8 RAJESH */
  66.     lap_hdr->lap_ls.lap_dsap = HEX_AA;
  67.     lap_hdr->lap_ls.lap_ssap = HEX_AA;
  68.     lap_hdr->lap_ls.lap_cntl = HEX_3;
  69.     lap_hdr->lap_ls.lap_orghi = 0;
  70.     lap_hdr->lap_ls.lap_orglo = 0;
  71.     lap_hdr->lap_ls.lap_type = LAP_ARP;
  72.  
  73.     arp_hdr = (struct arp_header *)(lap_hdr+1);
  74.     ipb->ip.ptr = (struct ip4_header *)arp_hdr;    /* reuse this entry for ARP's header */
  75.     ipb->ip.length = sizeof(struct arp_header);
  76.     ipb->tp.length = 0;
  77.     
  78.     arp_hdr->arp_hardware = ARP_ETHERNET;
  79.     arp_hdr->arp_protocol = LAP_IP;
  80.     arp_hdr->arp_hlen = sizeof(struct Lap802_addr);
  81.     arp_hdr->arp_plen = sizeof(ip_addr);
  82.     arp_hdr->arp_sha = lap->our_lap_addr;
  83.     ipb->iop.ioCompletion = nil;
  84.  
  85.     /* insert task into the vertical retrace queue to time-out ARP requests 
  86.        and age ARP cache entries */
  87.     lap->arp_vrt_info.VBL.qType = vType;
  88.     lap->arp_vrt_info.VBL.vblAddr = Arp_vrt_handler;
  89.     lap->arp_vrt_info.VBL.vblCount = ARP_VRT_COUNT;
  90.     lap->arp_vrt_info.VBL.vblPhase = ARP_VRT_PHASE;
  91.     lap->arp_vrt_info.vblA5 = (Ptr)lap;
  92.     
  93.     return(VInstall((QElemPtr)&lap->arp_vrt_info.VBL));
  94.     }
  95.  
  96. /* Arp_vrt_handler is called by the vertical retrace manager to age ARP cache entries and
  97.    retransmit ARP requests.  A0 = VBLTask entry */
  98.    
  99. pascal void Arp_vrt_handler()
  100. {
  101.     struct Lap802Info *lap;
  102.     struct ipbuf *ipb;
  103.     struct ipbuf *next_ipb;
  104.     struct arp_entry *ap;
  105.     struct arp_info *arp;
  106.     short oldPS;
  107.     
  108.     lap = (struct Lap802Info *) ((struct VBLTaskA5 *) GetA0())->vblA5;
  109.     lap->arp_vrt_info.VBL.vblCount = ARP_VRT_COUNT;
  110.     
  111.     /* crawl through ARP queue timing out packets */
  112.     oldPS = Disable();
  113.     ipb = (struct ipbuf *)lap->arp_q.qHead;
  114.     while (ipb) {
  115.         next_ipb = (struct ipbuf *)ipb->iop.qLink;
  116.         arp = (struct arp_info *)ipb->laphdr.ptr;
  117.         arp->timer--;
  118.         if (arp->timer < 0) {
  119.             /* packet has timed out */
  120.             arp->rtx++;
  121.             if (arp->rtx < MAX_RTX) {
  122.                 /* we'll try again and send an ARP */
  123.                 arp->timer = 3;
  124.                 SendARP(lap, ARP_REQUEST, arp->addr, &lap->lap_broadcast_addr);
  125.                 }
  126.             else {
  127.                 /* no-one responded to the ARP, discard packet in error */
  128.                 Dequeue((QElemPtr)ipb, &lap->arp_q);
  129.                 ipb->iop.ioResult = ipDestDeadErr;
  130.                 IOComplete(ipb);
  131.                 }
  132.             }
  133.         ipb = next_ipb;
  134.         }
  135.         
  136.     /* now time-out ARP table entries */
  137.     for (ap = &lap->arp_table[0]; ap < &lap->arp_table[ARP_TABLE_SIZE]; ap++) {
  138.         if (ap->ip_address != nil) {
  139.             ap->age++;
  140.             if (ap->age > MAX_AGE) {
  141.                 ap->ip_address = nil;
  142.                 }
  143.             }
  144.         }
  145.     Enable(oldPS);
  146.     }
  147.  
  148.  
  149. /* Arp_read_ph is called directly by the IEEE 802.3 packet read handler when an
  150.    ARP type packet is received. */
  151.  
  152. void Arp_read_ph(rds)
  153. struct rdStruct *rds;
  154. {
  155.     struct Lap802Info     *lap;
  156.     struct arp_entry    *ap;
  157.     struct Lap802_header     *lap_hdr;
  158.     struct ipbuf *ipb;
  159.     struct ipbuf *next_ipb;
  160.     short oldPS;
  161.  
  162.     lap = (struct Lap802Info *) rds->lap;
  163.  
  164.     /* call ReadRest to finish reading in packet, but only enough 
  165.        for IP-type ARPs */
  166.     if (ReadRest(rds, (char *)&lap->arp_rcv, sizeof(lap->arp_rcv)) <= 0) {
  167.         /* if enough received, check ARP header */
  168.            if ((lap->arp_rcv.arp_hardware == ARP_ETHERNET) &&
  169.            (lap->arp_rcv.arp_protocol == LAP_IP)) {
  170.             /* Is the pair <protocol type, sender protocol address> 
  171.                already in the arp table? */
  172.             oldPS = Disable();
  173.              ap = get_arp_entry(lap,lap->arp_rcv.arp_spa);
  174.  
  175.             if (ap) {
  176.                 /* If yes, update with the new hardware address */
  177.                 ap->lap_address = lap->arp_rcv.arp_sha;
  178.                 }
  179.  
  180.             if ((lap->arp_rcv.arp_spa == lap->our_ip_addr) &&
  181.                (lap->arp_rcv.arp_opcode == ARP_REPLY)) {
  182.                 /* we have received a reply when we ARPed on our address */
  183.                 lap->addressConflict = true;
  184.                 }
  185.             else if (lap->arp_rcv.arp_tpa == lap->our_ip_addr) {
  186.                 /* since packet sent to us, process it */
  187.                 if (ap == nil) {
  188.                     /* Save sender entry in table since this host will 
  189.                        probably want to talk to us soon */
  190.                     ap = new_arp_entry(lap, lap->arp_rcv.arp_protocol,
  191.                         lap->arp_rcv.arp_sha, lap->arp_rcv.arp_spa);
  192.                     }
  193.  
  194.                 /* Look at opcode */
  195.                 if (lap->arp_rcv.arp_opcode == ARP_REQUEST) {
  196.                     /* response with our IEEE 802.3 address */
  197.                     SendARP (lap, ARP_REPLY, lap->arp_rcv.arp_spa,
  198.                         &((struct Lap802_header *)rds->laphdr.ptr)->lap_src);
  199.                     }
  200.                 else if (lap->arp_rcv.arp_opcode == ARP_REPLY) {
  201.                     /* dequeue packet waiting ARP and send it */
  202.                     ipb = (struct ipbuf *)lap->arp_q.qHead;
  203.                     while (ipb) {
  204.                         next_ipb = (struct ipbuf *)ipb->iop.qLink;
  205.                         if (((struct arp_info *)(ipb->laphdr.ptr))->addr == ap->ip_address) {
  206.                             /* dequeue packet from ARP queue and send it */
  207.                             ap->age = 0;
  208.                             lap_hdr = (struct Lap802_header *)ipb->laphdr.ptr;
  209.                             lap_hdr->lap_dest = ap->lap_address;
  210.                             lap_hdr->lap_ls.lap_type = LAP_IP;
  211.                             Dequeue((QElemPtr)ipb, &lap->arp_q);
  212.                             /* start IEEE 802.3 output */
  213.                             Lap802_writeit(lap, ipb);
  214.                              }
  215.                           /* look at next packet in queue */
  216.                           ipb = next_ipb;
  217.                         }
  218.                     }
  219.                 }
  220.             Enable(oldPS);
  221.             }
  222.         }
  223.     }
  224.  
  225. /* RARP_read_ph is called directly by the IEEE 802.3 packet read handler when an
  226.    RARP type packet is received. */
  227.    
  228. void RARP_read_ph(rds)
  229. struct rdStruct *rds;
  230. {
  231.     struct Lap802Info *lap;
  232.  
  233.     lap = (struct Lap802Info *) rds->lap;
  234.  
  235.     /* call ReadRest to finish reading in packet, but only enough 
  236.        for IP-type RARPs */
  237.     if (ReadRest(rds, (char *)&lap->arp_rcv, sizeof(lap->arp_rcv)) <= 0) {
  238.         /* if enough received, check RARP header */
  239.         if ((rds->lapBroadcast == false) && 
  240.             (lap->arp_rcv.arp_hardware == ARP_ETHERNET) &&
  241.             (lap->arp_rcv.arp_tha.lap_lo == lap->our_lap_addr.lap_lo)) {
  242.             /* since packet sent to us (most likely), process it */
  243.             /* Look at opcode */
  244.             if (lap->arp_rcv.arp_opcode == RARP_REPLY) {
  245.                 if (lap->our_ip_addr == 0) {
  246.                     /* our address is unknown, take it from RARP reply */
  247.                     lap->our_ip_addr = lap->arp_rcv.arp_tpa;
  248.                     lap->lc.configIPAddr = LAPcnfg;
  249.                     }
  250.                 }
  251.             }
  252.         }
  253.     }    
  254.  
  255. /* IP_to_Lap802 is called to translate an IP address into an IEEE 802.3 
  256.    address by using ARP */
  257.  
  258. struct Lap802_addr *IP_to_Lap802(lap, addr)
  259. struct Lap802Info *lap;
  260. ip_addr addr;
  261. {
  262.     struct arp_entry *ap;
  263.     struct Lap802_addr *enp;
  264.     short oldPS;
  265.     
  266.     if (broadcastAddr((struct LAPInfo *)lap, addr))
  267.         /* convert IP broadcast address into IEEE 802.3 broadcast */
  268.         return(&lap->lap_broadcast_addr);
  269.     
  270.     /* check if our IP address, if so, return our Lap802 address since we won't
  271.        respond to the ARP */
  272.     if (addr == lap->our_ip_addr)
  273.         return(&lap->our_lap_addr);
  274.         
  275.     /* search through ARP table */
  276.     oldPS = Disable();
  277.     ap = get_arp_entry(lap, addr);
  278.     if (ap) {
  279.         /* reset age field to reflect access */
  280.         ap->age = 0;
  281.         enp = &ap->lap_address;
  282.         }
  283.     else
  284.         enp = nil;
  285.     Enable(oldPS);
  286.     return(enp);
  287.     }
  288.     
  289.     
  290. void Arp_close(lap)
  291. struct Lap802Info *lap;
  292. {
  293.     VRemove((QElemPtr)&lap->arp_vrt_info.VBL);
  294.     DisposPtr((Ptr)lap->arp_ipb);
  295.     lap->arp_ipb = nil;
  296.     }
  297.     
  298.     
  299. void SendARP (lap,arp_code,ip_dest,lap_dest)
  300. struct Lap802Info *lap;
  301. int arp_code;
  302. ip_addr ip_dest;
  303. Lap802_addr *lap_dest;
  304. {
  305.     struct ipbuf *ipb;
  306.     struct arp_header *arp_hdr;
  307.     struct Lap802_header *lap_hdr;
  308.     short oldPS;
  309.     
  310.     ipb = lap->arp_ipb;       
  311.     oldPS = Disable();
  312.  
  313.     if (ipb->iop.ioResult <= 0) {
  314.         /* ipbuf available for sending ARPs */
  315.  
  316.         lap_hdr = (struct Lap802_header *)ipb->laphdr.ptr;
  317.             lap_hdr->lap_dest = *lap_dest;
  318.         lap_hdr->lap_ls.lap_type = LAP_ARP;
  319.  
  320.            arp_hdr = (struct arp_header *)ipb->ip.ptr;
  321.             arp_hdr->arp_opcode = arp_code;
  322.             arp_hdr->arp_sha = lap->our_lap_addr;
  323.         arp_hdr->arp_spa = lap->our_ip_addr;
  324.         arp_hdr->arp_tha = *lap_dest;
  325.         arp_hdr->arp_tpa = ip_dest;
  326.  
  327.         /* call the IEEE 802.3 direct-write routine since we don't want to search the
  328.            ARP table again! */
  329.         Lap802_writeit(lap, ipb);
  330.         }
  331.     Enable(oldPS);
  332.     }
  333.     
  334.  
  335. /* get_arp_entry is called to return a pointer to the ARP entry for the
  336.    indicated IP address.  Must be called with interrupts DISABLED to ensure
  337.    consistent state of ARP table. */
  338.    
  339. struct arp_entry *get_arp_entry(lap, addr)
  340. struct Lap802Info *lap;
  341. ip_addr addr;
  342. {
  343.     struct arp_entry *ap;
  344.     
  345.     for (ap = &lap->arp_table[0]; ap < &lap->arp_table[ARP_TABLE_SIZE]; ap++) {
  346.         /* Is the pair <protocol type, protocol address> in the arp table? */
  347.         if (ap->ip_address == addr) {
  348.             /* If yes, return entry pointer */
  349.             return(ap);
  350.             }
  351.         }
  352.     return(nil);
  353.     }
  354.  
  355. /* new_arp_entry is called to return a pointer to a new ARP entry in the ARP table.
  356.    Either an unused entry or the old entry in the table is returned. Interrupts
  357.    must be disabled when calling this routine */
  358.    
  359. struct arp_entry *new_arp_entry(lap, prot, sha, spa)
  360. struct Lap802Info *lap;
  361. b_16 prot;                
  362. Lap802_addr sha;    
  363. ip_addr spa;
  364. {
  365.     struct arp_entry *ap, *oldest_ap;
  366.     int oldest_age;
  367.     short oldPS;
  368.     
  369.     ap = &lap->arp_table[0];
  370.  
  371.     oldPS = Disable();
  372.     oldest_ap = ap;
  373.     oldest_age = ap->age;
  374.     for (; ap < &lap->arp_table[ARP_TABLE_SIZE]; ap++) {
  375.         if (ap->ip_address == 0) {
  376.             /* found unused entry, return it */
  377.             oldest_ap = ap;
  378.             break;
  379.             }
  380.         else if (ap->age > oldest_age) {
  381.             oldest_ap = ap;
  382.             oldest_age = ap->age;
  383.             }
  384.         }
  385.  
  386.     oldest_ap->age = 0;
  387.     oldest_ap->protocol = prot;
  388.     oldest_ap->lap_address = sha;
  389.     oldest_ap->ip_address = spa;
  390.  
  391.     Enable(oldPS);
  392.     return(oldest_ap);
  393.     }
  394.     
  395. void del_arp_entry(lap, addr)
  396. struct Lap802Info *lap;
  397. ip_addr addr;
  398. {
  399.     struct arp_entry *ap;
  400.     short oldPS;
  401.     
  402.     oldPS = Disable();
  403.     for (ap = &lap->arp_table[0]; ap < &lap->arp_table[ARP_TABLE_SIZE]; ap++) {
  404.         /* Is the pair <protocol type, protocol address> in the arp table? */
  405.         if (ap->ip_address == addr) {
  406.             /* If yes, zero its entry */
  407.             bzero((Ptr)ap, sizeof(struct arp_entry));
  408.             break;
  409.             }
  410.         }
  411.     Enable(oldPS);
  412.     }
  413.  
  414. /* BroadcastAddr is called to verify that the indicated address isn't a
  415.    broadcast address */
  416.    
  417. Boolean broadcastAddr(lap, addr)
  418. struct LAPInfo *lap;
  419. ip_addr addr;
  420. {
  421.     ip_addr netmask;
  422.     
  423.     /* check for 255.255.255.255 broadcast addr */
  424.     if (addr == 0xffffffff)
  425.         return(true);
  426.         
  427.     /* check for net.subnet.255.255 broadcast addr */
  428.     if ((addr | lap->our_net_mask) == 0xffffffff)
  429.         return(true);
  430.     
  431.     /* check for net.255.255.255 broadcast addr */
  432.     if ((lap->our_ip_addr & 0x80000000) == 0)
  433.         netmask = 0xFF000000;
  434.     else if ((lap->our_ip_addr & 0x40000000) == 0)
  435.         netmask = 0xFFFF0000;
  436.     else
  437.         netmask = 0xFFFFFF00;            
  438.     if ((addr | netmask) == 0xffffffff)
  439.         return(true);
  440.  
  441.     /* check for 0.0.0.0 broadcast addr */
  442.     if (addr == 0x0)
  443.         return(true);
  444.  
  445.     /* check for net.subnet.0.0 broadcast addr */
  446.     if (addr == (lap->our_ip_addr & netmask))
  447.         return(true);
  448.     return(false);
  449.     }
  450.